﻿using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Agile.Redsys
{
    public class RedsysRedirectionBuilder
    {
        private readonly object _textHtmlAttributes;
        private readonly object _submitButtonHtmlAttributes;

        /// <summary>
        /// Gets the commerce.
        /// </summary>
        /// <value>The commerce.</value>
        public Commerce Commerce { get; private set; }

        

        /// <summary>
        /// Initializes a new instance of the <see cref="RedsysRedirectionBuilder" /> class.
        /// </summary>
        /// <param name="Commerce">The commerce.</param>
        /// <param name="TextHtmlAttributes">The redirect text HTML attributes.</param>
        /// <param name="SubmitButtonHtmlAttributes">The button HTML attributes.</param>
        public RedsysRedirectionBuilder(Commerce Commerce, object TextHtmlAttributes = null, object SubmitButtonHtmlAttributes = null)
        {
            _textHtmlAttributes = TextHtmlAttributes;
            _submitButtonHtmlAttributes = SubmitButtonHtmlAttributes;
            this.Commerce = Commerce;
        }

        /// <summary>
        /// Creates HTML for an authorization request.
        /// </summary>
        /// <param name="authorization">The authorization.</param>
        /// <param name="writer">The writer.</param>
        public void CreateHtmlFor(RedsysAuthorizationRequest authorization, TextWriter writer)
        {



            writer.WriteLine("<html>");
            writer.WriteLine("<head>");
            writer.WriteLine("</head>");
            writer.WriteLine(Commerce.TestEnviroment ? "<body>" : "<body onload=\"document.getElementById('theForm').submit();\">");

            CreateFormFor(authorization, writer);

            writer.WriteLine("</body>");
            writer.WriteLine("</html>");
        }
#if DEBUG
        public static IPAddress GetPublicIpAddress()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://ifconfig.me");
            request.Method = "GET";
            request.UserAgent = "curl"; // this simulate curl linux command

            using (WebResponse response = request.GetResponse())
            using (var reader = new StreamReader(response.GetResponseStream()))
            {
                string ipString = reader.ReadToEnd().Replace("\n", "");
                return IPAddress.Parse(ipString);
            }
        }
#endif

        private static string GetNotificationUrl()
        {
            UrlHelper urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
            string callback = urlHelper.Action("Callback", "Redsys", new {},"http");

#if DEBUG
            UriBuilder uriBuilder = new UriBuilder(callback);
            uriBuilder.Host = GetPublicIpAddress().ToString();
            uriBuilder.Port = 7272;
            callback = uriBuilder.Uri.ToString();
            
#endif
            return callback;
        }
        /// <summary>
        /// Creates a form for an authorization request.
        /// </summary>
        /// <param name="authorization">The authorization.</param>
        /// <param name="writer">The writer.</param>
        private void CreateFormFor(RedsysAuthorizationRequest authorization, TextWriter writer)
        {
            string notificationUrl = GetNotificationUrl();
            int amount = (int)Math.Round(authorization.Amount * 100, 2);
            string url = Commerce.TestEnviroment ? "https://sis-t.redsys.es:25443/sis/realizarPago" : "https://sis.redsys.es/sis/realizarPago";
            string signature = SignatureHelper.GetSignature(amount,
                                                            authorization.Order,
                                                            Commerce.MerchantCode,
                                                            authorization.Currency,
                                                            RedsysTransactionType.Authorization,
                                                            notificationUrl,
                                                            Commerce.Secret);

            writer.WriteLine("<form id=\"theForm\" action=\"{0}\" method=\"POST\" >", url);
            
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />",
                             "Ds_Merchant_Amount",
                             amount);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_Currency", authorization.Currency);

            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_MerchantCode", Commerce.MerchantCode);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_MerchantData", authorization.MerchantData);
            
            
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />",
                             "Ds_Merchant_MerchantSignature",
                             signature);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_ProductDescription", authorization.Product);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_MerchantURL", notificationUrl);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_Order", authorization.Order);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_Terminal", Commerce.Terminal);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_Titular", authorization.Client);

            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />",
                             "Ds_Merchant_TransactionType",
                             (char)RedsysTransactionType.Authorization);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_UrlOK", authorization.OnSuccess);


            TagBuilder spanBuilder = new TagBuilder("span");
            spanBuilder.SetInnerText(Localization.IfNotRedirectedClick + " ");
            if(_textHtmlAttributes != null)
                spanBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(_textHtmlAttributes));

            writer.WriteLine(spanBuilder.ToString());

            TagBuilder submitBuilder = new TagBuilder("input");
            submitBuilder.Attributes["type"] = "submit";
            submitBuilder.Attributes["value"] = Localization.Here;

            if (_submitButtonHtmlAttributes != null)
                submitBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(_submitButtonHtmlAttributes));
            writer.WriteLine(submitBuilder.ToString());

            writer.WriteLine("</form>");
        }

        /// <summary>
        /// Creates HTML for a recurring transaction request.
        /// </summary>
        /// <param name="recurringTransaction">The recurring transaction.</param>
        /// <param name="writer">The writer.</param>
        public void CreateHtmlFor(RedsysRecurringTransactionRequest recurringTransaction, TextWriter writer)
        {



            writer.WriteLine("<html>");
            writer.WriteLine("<head>");
            writer.WriteLine("</head>");

            CreateFormFor(recurringTransaction, writer);
            writer.WriteLine("</body>");
            writer.WriteLine("</html>");
        }

        /// <summary>
        /// Creates a form for a recurring transaction request.
        /// </summary>
        /// <param name="recurringTransaction">The recurring transaction.</param>
        /// <param name="writer">The writer.</param>
        private void CreateFormFor(RedsysRecurringTransactionRequest recurringTransaction, TextWriter writer)
        {
            int amount = (int)Math.Round(recurringTransaction.Amount * 100, 2);
            string url = Commerce.TestEnviroment ? "https://sis-t.redsys.es:25443/sis/realizarPago" : "https://sis.redsys.es/sis/realizarPago";
            string chargeExpireDate = (DateTime.Now + TimeSpan.FromDays(recurringTransaction.Recurrences * recurringTransaction.Frequency)).ToString("yyyy-MM-dd");
            int sum = amount * recurringTransaction.Recurrences;
            string notificationUrl = GetNotificationUrl();

            string signature = SignatureHelper.GetSignature(amount,
                                                            recurringTransaction.Order,
                                                            Commerce.MerchantCode,
                                                            recurringTransaction.Currency,
                                                            sum,
                                                            RedsysTransactionType.RecurringTransaction,
                                                            notificationUrl,
                                                            Commerce.Secret);

            writer.WriteLine(Commerce.TestEnviroment ? "<body>" : "<body onload=\"document.getElementById('theForm').submit();\">");

            writer.WriteLine("<form id=\"theForm\" action=\"{0}\" method=\"POST\" >", url);
            

            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />",
                             "Ds_Merchant_Amount",
                             amount);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_Currency", recurringTransaction.Currency);

            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_DateFrecuency", recurringTransaction.Frequency);
           
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />",
                             "Ds_Merchant_SumTotal",
                             sum);
            
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />",
                             "Ds_Merchant_ChargeExpiryDate",
                             chargeExpireDate);

            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_MerchantCode", Commerce.MerchantCode);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_MerchantData", recurringTransaction.MerchantData);
            
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />",
                             "Ds_Merchant_MerchantSignature",
                             signature);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_ProductDescription", recurringTransaction.Product);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_MerchantURL", notificationUrl);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_Order", recurringTransaction.Order);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_Terminal", Commerce.Terminal);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_Titular", recurringTransaction.Client);

            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />",
                             "Ds_Merchant_TransactionType",
                             (char)RedsysTransactionType.RecurringTransaction);
            writer.WriteLine("<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />", "Ds_Merchant_UrlOK", recurringTransaction.OnSuccess);

            TagBuilder spanBuilder = new TagBuilder("span");
            spanBuilder.SetInnerText(Localization.IfNotRedirectedClick + " ");
            if (_textHtmlAttributes != null)
                spanBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(_textHtmlAttributes));
            writer.WriteLine(spanBuilder.ToString());

            TagBuilder submitBuilder = new TagBuilder("input");
            submitBuilder.Attributes["type"] = "submit";
            submitBuilder.Attributes["value"] = Localization.Here;

            if (_submitButtonHtmlAttributes != null)
                submitBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(_submitButtonHtmlAttributes));
            writer.WriteLine(submitBuilder.ToString());

            writer.WriteLine("</form>");

           
        }
    }
}
